package ic.symbols;

import common.exceptions.SemanticError;
import ic.ast.Visitor;
import ic.ast.decl.Parameter;
import ic.ast.stmt.LocalVariable;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: Matan
 * Date: 12/10/13
 * Time: 11:34 AM
 */
public class MethodSymbolTable extends BlockSymbolTable {

    private boolean isStatic;
    private Map<String, VarSymbol> parameters = new LinkedHashMap<String, VarSymbol>();

    public MethodSymbolTable(SymbolTable parent, String name, boolean isStatic) {
        super(parent, name);
        this.isStatic = isStatic;
        this.blockDepth = 1;
    }

    @Override
    public Symbol lookup(String name) {
        if (parameters.containsKey(name)) {
            return parameters.get(name);
        } else if (locals.containsKey(name)) {
            return locals.get(name);
        } else return parent.lookup(name);
    }

    @Override
    public SymbolTable lookupTable(String name) {
        if (parameters.containsKey(name) || locals.containsKey(name)) {
            return this;
        } else return parent.lookupTable(name);
    }

    @Override
    public Symbol staticLookup(String name) {
        if (parameters.containsKey(name)) {
            return parameters.get(name);
        } else if (locals.containsKey(name)) {
            return locals.get(name);
        } else return null;
    }

    @Override
    public void insert(LocalVariable local) throws Exception {
        if (locals.containsKey(local.getName())) {
            throw new SemanticError("Id " + local.getName() + " already defined in current scope");
        }
        if (parameters.containsKey(local.getName())) {
            throw new SemanticError("Local variable " + local.getName() + " is shadowing a parameter");
        }
        locals.put(local.getName(), new VarSymbol(local));
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return getName();
    }

    @Override
    public Object accept(Visitor visitor) throws Exception {
        return visitor.visit(this);
    }

    @Override
    public String getCurrentMethodName() {
        return this.getName();
    }

    public boolean isStatic() {
        return isStatic;
    }

    public List<VarSymbol> getParameterSymbols() {
        return new LinkedList<VarSymbol>(parameters.values());
    }

    public void insert(Parameter formal) throws Exception {
        if (locals.containsKey(formal.getName())) {
            throw new SemanticError("Id " + formal.getName() + " already defined in current scope");
        }
        if (parameters.containsKey(formal.getName())) {
            throw new SemanticError("Id " + formal.getName() + " already defined in current scope");
        }
        parameters.put(formal.getName(), new VarSymbol(formal));
    }
}

